package com.wn.base.algorithm;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;

import java.util.*;
import java.util.concurrent.LinkedBlockingDeque;

/**
 * @FileName: Demo1
 * @Description: TODO
 * @Author: MaWenHao
 * @Created: 2020/11/20 - 11:12
 * @Version: V1.0
 * @Company: 东方微银科技（北京）有限公司
 */
public class Test {

    private static final String DECISION_FIELD = IdUtil.fastSimpleUUID();

    private static  Map<String, Map<String, Integer>> cache = new HashMap<>();

    public static void main(String[] args) {
        // 构造条件树
        Map<String, Node<Integer>> conditionTrees = Test.buildConditionTree();
        // 加载实体数据
        List<Person> entities = Test.buildEntities();
        // 判断数据集是否协调
        boolean isCoordinate = Test.isCoordinate(conditionTrees, entities);
        if (!isCoordinate) {
            System.out.println("数据集不协调,程序终止!");
            return;
        }

    }

    private static boolean isCoordinate(Map<String, Node<Integer>> conditionTrees, List<Person> persons) {
        // 重置缓存
        Test.resetScoreCache(conditionTrees);
        // 条件属性的优势集
        Set<String> rA = new HashSet<>(8);
        // 包含决策属性的优势集
        Set<String> rD = new HashSet<>(8);

        for (Person x : persons) {
            for (Person y : persons) {
                // 获取条件属性
                Map<String, String> conditionFieldX = x.getConditionFields();
                Map<String, String> conditionFieldY = y.getConditionFields();
                // x和y组合的唯一id
                String serial = x.getId() + y.getId();
                // 判断y相对于x在条件列上是否优势
                boolean isCondAdvantage = Test.isCondAdvantage(conditionFieldX, conditionFieldY, conditionTrees);
                if (isCondAdvantage) {
                    rA.add(serial);
                }
                // 判断y是不是x的决策优势对象
                boolean isDecisionAdvantage = Test.isDecisionAdvantage(x, y);
                if (isCondAdvantage && isDecisionAdvantage) {
                    rD.add(serial);
                }
            }
        }
        // 计算数据集是否协调
        return Test.isCoordinate(rA, rD);
    }

    /**
     * 计算set1中的所有元素是否都在set2中
     * @param set1
     * @param set2
     * @return
     */
    private static boolean isCoordinate(Set<String> set1, Set<String> set2) {
        for (String ra : set1) {
            if (!set2.contains(ra)) {
                return false;
            }
        }
        return true;
    }

    private static boolean isDecisionAdvantage(Person x, Person y) {
        return x.getDecision() <= y.getDecision();
    }

    private static void resetScoreCache(Map<String, Node<Integer>> conditionTrees) {
        cache = new HashMap<>(8);
        Set<String> keySet = conditionTrees.keySet();
        for (String key : keySet) {
            cache.put(key, new HashMap<>());
        }
    }

    private static boolean isCondAdvantage(Map<String, String> conditionFieldX, Map<String, String> conditionFieldY, Map<String, Node<Integer>> conditionTrees) {
        Set<Map.Entry<String, Node<Integer>>> entries = conditionTrees.entrySet();
        for (Map.Entry<String, Node<Integer>> entry : entries) {
            String key = entry.getKey();
            String valueX = conditionFieldX.get(key);
            String valueY = conditionFieldY.get(key);
            Integer lastScoreX = Test.getLastScore(key, valueX, entry.getValue());
            Integer lastScoreY = Test.getLastScore(key, valueY, entry.getValue());
            if (lastScoreX > lastScoreY) {
                return false;
            }
        }
        return true;
    }

    private static Integer getLastScore(String key, String value, Node<Integer> node) {
        Map<String, Integer> valueCacheMap = cache.get(key);
        Integer scoreCache = valueCacheMap.get(value);
        if (ObjectUtil.isEmpty(scoreCache)) {
            Queue<Node<Integer>> cacheQueue = new LinkedBlockingDeque<>();
            cacheQueue.add(node);
            while (cacheQueue.size() > 0) {
                Node<Integer> head = cacheQueue.poll();
                if (CollectionUtil.isEmpty(head.getNextList())) {
                    boolean match = head.match(value);
                    if (match) {
                        Integer score = head.getScore();
                        valueCacheMap.put(value, score);
                        return score;
                    }
                }
            }
        }
        return null;
    }

    private static List<Person> buildEntities() {
        return null;
    }

    private static Map<String, Node<Integer>> buildConditionTree() {
        return null;
    }

}
